/* $Id: list.c 13 2006-12-14 21:07:45Z judas $ */

#include <nih/cdefs.h>

#include <nih/list.h>

#include <errno.h>
#include <stdlib.h>

struct nih_llist *nih_lcreate(struct nih_llist *next, const void *value)
{
        struct nih_llist *node;

        node = calloc(1, sizeof(struct nih_llist));

        if (node) {
                node->next = next;
                node->value = (void *) value;
        }

        return node;
}

struct nih_llist *nih_lremove_deep(struct nih_llist *llist,
                                   nih_free_fnc *free_fnc)
{
        struct nih_llist *nhead;

        nhead = NULL;

        if (!llist)
                errno = EINVAL;
        else {
                if (llist->next)
                        nhead = llist->next;
                nih_free_call(free_fnc, llist->value);
                free(llist);
        }

        if (!nhead)
                errno = ESRCH;

        return nhead;
}

inline struct nih_llist *nih_lremove(struct nih_llist *llist)
{
        return nih_lremove_deep(llist, NULL);
}

int nih_ldestroy_deep(struct nih_llist *llist, nih_free_fnc *free_fnc)
{
        int res;

        res = -1;

        if (!llist)
                errno = EINVAL;
        else {
                do {} while (nih_lremove_deep(llist, free_fnc) == 0);
                if (errno == ESRCH)
                        res = 0;
        }

        return res;
}

inline int nih_ldestroy(struct nih_llist *llist)
{
        return nih_ldestroy_deep(llist, NULL);
}

struct nih_dlist *nih_dcreate(struct nih_dlist *prev, struct nih_dlist *next,
                              const void *value)
{
        struct nih_dlist *node;

        node = calloc(1, sizeof(struct nih_dlist));

        if (node) {
                if ((node->prev = prev))
                        node->prev->next = node;
                if ((node->next = next))
                        node->next->prev = node;
                node->value = (void *) value;
        }

        return node;
}

struct nih_dlist *nih_dremove_deep(struct nih_dlist *dlist,
                                   nih_free_fnc *free_fnc)
{
        struct nih_dlist *nhead;

        nhead = NULL;

        if (!dlist)
                errno = EINVAL;
        else {

                if (dlist->prev) {
                        dlist->prev->next = dlist->next;
                        nhead = dlist->prev;
                }
                if (dlist->next) {
                        dlist->next->prev = dlist->prev;
                        nhead = dlist->next;
                }
                nih_free_call(free_fnc, dlist->value);
                free(dlist);
        }

        if (!nhead)
                errno = ESRCH;

        return nhead;
}

inline struct nih_dlist *nih_dremove(struct nih_dlist *dlist)
{
        return nih_dremove_deep(dlist, NULL);
}

int nih_ddestroy_deep(struct nih_dlist *dlist, nih_free_fnc *free_fnc)
{
        int res;

        res = -1;

        if (!dlist)
                errno = EINVAL;
        else {
                do {} while ((dlist = nih_dremove_deep(dlist, free_fnc)));
                if (errno == ESRCH)
                        res = 0;
        }

        return res;
}

inline int nih_ddestroy(struct nih_dlist *dlist)
{
        return nih_ddestroy_deep(dlist, NULL);
}

